package com.millstein.tsinglog.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.millstein.tsinglog.commons.constant.SystemConstant;
import com.millstein.tsinglog.commons.enums.ResultCode;
import com.millstein.tsinglog.exception.TsinglogException;
import com.millstein.tsinglog.commons.service.BaseService;
import com.millstein.tsinglog.mapper.biz.CategoryMapper;
import com.millstein.tsinglog.mapper.biz.TagMapper;
import com.millstein.tsinglog.model.dto.tag.TagSaveDTO;
import com.millstein.tsinglog.model.pojo.Tag;
import com.millstein.tsinglog.model.vo.biz.TagVo;
import com.millstein.tsinglog.model.vo.result.PageResult;
import com.millstein.tsinglog.service.TagService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;

@Service
public class TagServiceImpl extends BaseService implements TagService {

    @Autowired
    private TagMapper tagMapper;

    @Autowired
    private CategoryMapper categoryMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public PageResult<TagVo> getTagByPage(Integer currentPage, Integer pageSize, String keyword, Long cid) {
        // 1.对参数进行校验
        if (currentPage == null) {
            currentPage = SystemConstant.DEFAULT_CURRENT_PAGE;
        }
        if (pageSize == null) {
            pageSize = SystemConstant.DEFAULT_PAGE_SIZE;
        }
        Example example = new Example(Tag.class);
        Example.Criteria criteria = example.createCriteria();

        // 2.条件查询
        if (StringUtils.isNotBlank(keyword)) {
            criteria.andLike("tagName", "%" + keyword + "%");
        }
        if (cid != null) {
            criteria.andEqualTo("cid", cid);
        }
        // 3.过滤掉状态为删除的数据
        criteria.andEqualTo("status", SystemConstant.STATUS_ENTITY_NORMAL);
        // 4.按照排序字段的升序排序
        example.setOrderByClause("usable desc, sort asc");
        // 5.开始查询
        PageHelper.startPage(currentPage, pageSize);
        List<Tag> list = tagMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(list)) {
            throw new TsinglogException(ResultCode.RETURN_DATA_NOT_FOUND);
        }
        PageInfo<Tag> pageInfo = new PageInfo<Tag>(list);
        // 6.将List<Tag>转为List<TagVo>
        List<TagVo> listVo = new ArrayList<TagVo>();
        for (Tag tag: list) {
            TagVo vo = new TagVo(tag);
            String categoryName = categoryMapper.selectCategoryByPrimaryKeyForServer(tag.getCid()).getCategoryName();
            vo.setCategoryName(categoryName);
            listVo.add(vo);
        }
        return new PageResult<TagVo>(pageInfo.getTotal(), pageInfo.getPages(), listVo);
    }

    @Override
    public List<Tag> getTagByCid(Long cid) {
        if (cid == null) {
            throw new TsinglogException(ResultCode.PARAM_IS_BLANK);
        }
        Tag tag = new Tag();
        tag.setCid(cid);
        // 查询已启用的标签
        tag.setUsable(SystemConstant.USABLE_ENTITY_ON);
        tag.setStatus(SystemConstant.STATUS_ENTITY_NORMAL);
        List<Tag> list = tagMapper.select(tag);
        if (CollectionUtils.isEmpty(list)) {
            throw new TsinglogException(ResultCode.RETURN_DATA_NOT_FOUND);
        }
        return list;
    }

    private Tag getTagByTagName(String tagName) {
        Tag tag = new Tag();
        tag.setTagName(tagName);
        tag.setStatus(SystemConstant.STATUS_ENTITY_NORMAL);
        return tagMapper.select(tag).size() == 0 ? null: tagMapper.select(tag).get(0);
    }

    @Override
    public void insertTag(TagSaveDTO tagSaveDTO) {

        // 不能保存同名的标签
        if (this.getTagByTagName(tagSaveDTO.getName()) != null) {
            throw new TsinglogException(ResultCode.EXISTS_SAME_TAG);
        }

        Tag tag = new Tag();
        tag.setTagName(tagSaveDTO.getName());
        tag.setUsable(SystemConstant.USABLE_ENTITY_ON);
        tag.setCid(Long.parseLong(tagSaveDTO.getCategoryId()));
        tag.setDescription(tagSaveDTO.getDesc());
        tag.setStatus(SystemConstant.STATUS_ENTITY_NORMAL);
        // 如果不指定sort的值，那么默认设置为1，即最高优先级
        if (StringUtils.isNotBlank(tagSaveDTO.getSort())) {
            tag.setSort(Integer.parseInt(tagSaveDTO.getSort()));
        } else {
            tag.setSort(SystemConstant.FIRST_PRIORITY);
        }

        tag.setCreateTime(getCurrentDateStr());
        tag.setUpdateTime(getCurrentDateStr());

        int result = tagMapper.insert(tag);
        if (result != 1) {
            throw new TsinglogException(ResultCode.INSERT_FAILURE);
        }

        redisTemplate.delete(SystemConstant.REDIS_KEY_FOR_TAG_INFO);
    }

    @Override
    public void changeUsable(Long id, Short usable) {
        if (id == null || usable == null) {
            throw new TsinglogException(ResultCode.PARAM_IS_BLANK);
        }
        Tag tag = tagMapper.selectTagByPrimaryKeyForServer(id);
        if (tag == null) {
            throw new TsinglogException(ResultCode.RETURN_DATA_NOT_FOUND);
        }

        tag.setUsable(usable);
        tag.setUpdateTime(getCurrentDateStr());
        int result = tagMapper.updateByPrimaryKeySelective(tag);

        if (result != 1) {
            throw new TsinglogException(ResultCode.UPDATE_FAILURE);
        }

        redisTemplate.delete(SystemConstant.REDIS_KEY_FOR_TAG_INFO);
    }

    @Override
    @Transactional
    public void deleteByIds(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new TsinglogException(ResultCode.PARAM_IS_BLANK);
        }

        for (Long id: ids) {
            Tag tag = tagMapper.selectTagByPrimaryKeyForServer(id);
            if (tag == null) {
                throw new TsinglogException(ResultCode.RETURN_DATA_NOT_FOUND);
            }
            tag.setStatus(SystemConstant.STATUS_ENTITY_DELETE);
            tag.setUpdateTime(getCurrentDateStr());

            int result = tagMapper.updateByPrimaryKey(tag);
            if (result != 1) {
                throw new TsinglogException(ResultCode.DELETE_FAILURE);
            }
        }
        redisTemplate.delete(SystemConstant.REDIS_KEY_FOR_TAG_INFO);
    }

    @Override
    public Tag getTagById(Long id) {
        if (id == null) {
            throw new TsinglogException(ResultCode.PARAM_IS_BLANK);
        }

        Tag tag = tagMapper.selectTagByPrimaryKeyForServer(id);
        if (tag == null || tag.getStatus() == SystemConstant.STATUS_ENTITY_DELETE) {
            throw new TsinglogException(ResultCode.RETURN_DATA_NOT_FOUND);
        }
        return tag;
    }

    @Override
    public void updateTag(TagSaveDTO tagSaveDTO) {

        Long id = tagSaveDTO.getId();
        if (id == null) {
            throw new TsinglogException(ResultCode.RETURN_DATA_NOT_FOUND);
        }

        // 不能保存同名的标签
        if (this.getTagByTagName(tagSaveDTO.getName()) != null) {
            throw new TsinglogException(ResultCode.EXISTS_SAME_TAG);
        }

        Tag dbTag = tagMapper.selectTagByPrimaryKeyForServer(id);
        if (dbTag == null) {
            throw new TsinglogException(ResultCode.RETURN_DATA_NOT_FOUND);
        }

        dbTag.setTagName(tagSaveDTO.getName());
        dbTag.setDescription(tagSaveDTO.getDesc());
        dbTag.setSort(Integer.parseInt(tagSaveDTO.getSort()));
        dbTag.setCid(Long.parseLong(tagSaveDTO.getCategoryId()));
        dbTag.setUpdateTime(getCurrentDateStr());

        int result = tagMapper.updateByPrimaryKeySelective(dbTag);
        if (result != 1) {
            throw new TsinglogException(ResultCode.UPDATE_FAILURE);
        }
        redisTemplate.delete(SystemConstant.REDIS_KEY_FOR_TAG_INFO);
    }

    @Override
    public Map<String, Object> getTagListForPortal() {

        ValueOperations operations = redisTemplate.opsForValue();

        if (redisTemplate.hasKey(SystemConstant.REDIS_KEY_FOR_TAG_INFO)) {
            return (Map<String, Object>) operations.get(SystemConstant.REDIS_KEY_FOR_TAG_INFO);
        }

        Map<String, Object> tagMap = new HashMap<>();
        List<Map<String, Object>> list = tagMapper.getTagListForPortal();

        if (!CollectionUtils.isEmpty(list)) {
            List<Map<String, Object>> returnList = new ArrayList<>();
            int allCount = 0;
            for (Map<String, Object> map : list) {
                Map<String, Object> newMap = new HashMap<>();
                for (Map.Entry<String, Object> entry: map.entrySet()) {
                    if ("tag_name".equals(entry.getKey())) {
                        newMap.put("tagName", entry.getValue());
                    } else if ("id".equals(entry.getKey())) {
                        newMap.put(entry.getKey(), entry.getValue());
                        newMap.put("link", SystemConstant.PORTAL_SEARCH_URL + "?tid=" + entry.getValue());
                    } else if ("count".equals(entry.getKey())) {
                        allCount += ((Long) entry.getValue()).intValue();
                        newMap.put(entry.getKey(), entry.getValue());
                    }
                }
                returnList.add(newMap);
            }
            tagMap.put("list", returnList);
            tagMap.put("allCount", allCount);
        }
        operations.set(SystemConstant.REDIS_KEY_FOR_TAG_INFO, tagMap);


        return tagMap;
    }

    @Override
    public List<Tag> getTagInfoByTids(List<Long> tids) {

        if (CollectionUtils.isEmpty(tids)) {
            throw new TsinglogException(ResultCode.PARAM_IS_BLANK);
        }
        return tagMapper.selectByIdList(tids);
    }
}
